package com.peppa.common.grayconfig.Strategy;

import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.peppa.common.grayconfig.ThreadAttributes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.ribbon.eureka.EurekaServerIntrospector;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;

public class StrategyAbstract implements Strategy {
    final Logger logger = LoggerFactory.getLogger(getClass());
    public String name = "";
    private int order =0;

    public int getOrder(){
        return order;
    }

    public void setOrder(int order){
        this.order = order;
    }

    public int compareTo(Strategy strategy){
        return this.order - strategy.getOrder();
    }

    public String getName(){
        return name;
    }

    void setName(String name) {
        this.name = name;
    }

    public Server getServer(ILoadBalancer balancer){
        return null;
    }

    /**
     * 根据header中的某个属性，从server的eureka的meta中拿到某个正则，来选择合适的路由
     * @return Server
     */
    public Server getServerByHeader(ILoadBalancer balancer,String header_key,String strategy_key){
        String headervalue = ThreadAttributes.getHeaderValue(header_key);
        if(headervalue==null||headervalue.trim().equals("")) {
            return null;
        }
        return getServerByRegex(balancer,headervalue.trim(),strategy_key);
    }


    /**
     * 根据某个特征值，从server的eureka的meta中拿到某个正则，来选择合适的路由
     * @return Server
     */
    public Server getServerByRegex(ILoadBalancer balancer,String feature_value,String strategy_key){
        try {
            EurekaServerIntrospector serverIntrospector = new EurekaServerIntrospector();
            Server serverRet = null;
            int count = 0;

            while(true) {
                if (serverRet == null && count++ < 5) {
                    List<Server> servers = balancer.getAllServers();
                    List<Server> serversReach = balancer.getReachableServers();
                    if (serversReach.size() == 0 || servers.size() == 0) {
                        return null;
                    }
                    //按照eureka的metadata里的strategy_key=?来选择
                    List<Server> devlist = new ArrayList<>();
                    for (Server server : servers) {
                        Map metadata = serverIntrospector.getMetadata(server);
                        if (metadata.containsKey(strategy_key)) {
                            String metavalue = (String) metadata.get(strategy_key);
                            if (metadata == null){
                                continue;
                            }
                            metavalue = metavalue.trim();
                            if (metavalue.equals("no"))
                                continue;
                            try {
                                if (!metavalue.equals("") && Pattern.matches(metavalue, feature_value)) {
                                    devlist.add(server);
                                }
                            }catch (Exception e){
                                logger.error(strategy_key,e.getMessage());
                            }
                        }
                    }
                    if (devlist.size()==0)
                        return null;
                    serverRet = getRandom(devlist);
                    //做下面判断，是因为多线程情况下，Server的状态会变
                    if (serverRet == null) {
                        Thread.yield();
                    } else {
                        if (serverRet.isAlive() && serverRet.isReadyToServe()) {
                            return serverRet;
                        }
                    }
                    serverRet = null;
                    continue;
                }
                if (count >= 5) {
                    logger.warn("No available alive servers after 5 tries from load balancer: " + balancer);
                }

                return serverRet;
            }

        }catch (Exception e){
            logger.error(name.concat("选择异常"),e.getMessage());
        }
        return null;
    }

    /**
     * 返回任意一个server
     * @param devlist
     * @return Server
     */
    Server getRandom(List<Server> devlist){
        int devsize = devlist.size();
        if(devsize ==1 ) {
            try {
                logger.info(name.concat("策略命中一个Server").concat(devlist.get(0).getHost()));
            }catch (Exception e){
                e.printStackTrace();
            }
            return devlist.get(0);
        }
        if (devsize>1){
            int number = ThreadLocalRandom.current().nextInt(devsize);
            try {
                logger.info(String.format("%s策略命中%d个Server,choose%d",name,devsize,number).concat(devlist.get(number).getHost()));
            }catch (Exception e){
                e.printStackTrace();
            }
            return devlist.get(number);
        }
        return null;
    }

    /**
     * 返回指定ip地址的服务，如果没有返回null
     * @param ip
     * @param balancer
     * @return Server
     */
    Server getIpSameServer(String ip,ILoadBalancer balancer){
        try {
            Server serverRet = null;
            int count = 0;

            while(true) {
                if (serverRet == null && count++ < 5) {
                    List<Server> servers = balancer.getAllServers();
                    List<Server> serversReach = balancer.getReachableServers();
                    if (serversReach.size() == 0 || servers.size() == 0) {
                        return null;
                    }
                    List<Server> devlist = new ArrayList<>();
                    //            List<Server> servers = balancer.getReachableServers();
                    //优先选择ip与自己想同的
                    for (Server server : servers) {
                        if (server!=null && server.getHost().equals(ip)) {
//                            serverRet = server;
                            devlist.add(server);
                            continue;
                        }
                    }
                    if (devlist.size()==0)
                        return null;
                    serverRet = getRandom(devlist);
                    //做下面判断，是因为多线程情况下，Server的状态会变
                    if (serverRet == null) {
                        Thread.yield();
                    } else {
                        if (serverRet.isAlive() && serverRet.isReadyToServe()) {
                            return serverRet;
                        }
                    }
                    serverRet = null;
                    continue;
                }
                if (count >= 5) {
                    logger.warn("No available alive servers after 5 tries from load balancer: " + balancer);
                }

                return serverRet;
            }
        } catch (Exception e) {
            logger.error("ip相等判断异常", e.getMessage());
        }
        return null;
    }
}
